<script setup lang="ts">
import type { BlogCollectionItem, SQLOperator } from '@nuxt/content';
import { formatDate } from '~/shared/utils/date.util';

useSeoMeta({
  title: 'iamcola\' articles.',
});

const ALL_TAG_NAME = '全部';
const router = useRouter();
const searchText = ref('');
const page = ref(1);
const pageSize = ref(6);
const skip = computed(() => (page.value - 1) * pageSize.value);
const data = ref<Pick<BlogCollectionItem, "tags" | "image" | "date" | "path" | "title" | "description" | "seo" | "id">[]>([]);
const total = ref(0);
const showTags = ref([{ text: ALL_TAG_NAME }]);
const currentTag = ref(ALL_TAG_NAME);
const getSelectTag = computed(() => currentTag.value === ALL_TAG_NAME ? '' : currentTag.value);

const wheres = computed<{
  field: "title" | "tags" | "id";
  operator: SQLOperator;
  value: string;
}[]>(() => [{
  field: 'title',
  operator: 'LIKE',
  value: `%${searchText.value}%`
}, {
  field: 'tags',
  operator: 'LIKE',
  value: `%${getSelectTag.value}%`
}]);

type BlogKeys = keyof BlogCollectionItem;
const selectFields: BlogKeys[] = ['id', 'title', 'description', 'date', 'tags', 'image', 'path', 'seo'];

const getArticleList = async (
  pageSize: number,
  skip: number,
  wheres: {
    field: 'id' | 'title' | 'tags',
    operator: SQLOperator,
    value: string
}[] = []) => {
  const res = await useAsyncData(() => {
    const query = queryCollection('blog').select(...selectFields);
    if (wheres.length) {
      return query.select(...selectFields)
        .andWhere(q => {
          if (wheres?.length) {
            for (const where of wheres) {
              const { field, operator, value } = where;
              q.where(field, operator, value);
            }
          }
          return q;
        })
        .limit(pageSize)
        .skip(skip)
        .order('date', 'DESC')
        .all();
    }
    return query.select(...selectFields)
      .limit(pageSize)
      .skip(skip)
      .order('date', 'DESC')
      .all();
  });

  if (!res.data.value) {
    return [];
  }

  return res.data.value;
};


const getArticleTotal = async (
  wheres: {
    field: 'id' | 'title' | 'tags',
    operator: SQLOperator,
    value: string
  }[] = []
) => {
  const res = await useAsyncData(
    () => {
      const query = queryCollection('blog');
      if (wheres.length) {
        return query
          .andWhere(q => {
            if (wheres?.length) {
              for (const where of wheres) {
                const { field, operator, value } = where;
                q.where(field, operator, value);
              }
            }
            return q;
          })
          .count();
      }
      return query.count();
    }
  );

  if (!res.data.value) {
    return 0;
  }

  return res.data.value;
};

const getArticleTags = async () => {
  const res = await useAsyncData(
    () => queryCollection('blog').select('tags').all()
  );

  if (!res.data.value) {
    return [];
  }

  const tags = res.data.value.map(item => item.tags);
  const tagsRecord: Record<string, number> = {};
  for (const items of tags) {
    for (const item of items) {
      if (!tagsRecord[item]) {
        tagsRecord[item] = 0;
      }
      tagsRecord[item]++;
    }
  }

  const sortTags = Object.entries(tagsRecord).sort(([, v1], [, v2]) => v2 - v1).map(([k]) => k);
  return sortTags;
};


const initArticleData = async (
  wheres?: {
    field: 'id' | 'title' | 'tags',
    operator: SQLOperator,
    value: string
  }[]
) => {
  const _data = await getArticleList(pageSize.value, skip.value, wheres);
  data.value = _data;
};

const initArticleTotalData = async (
  wheres?: {
    field: 'id' | 'title' | 'tags',
    operator: SQLOperator,
    value: string
  }[]
) => {
  const count = await getArticleTotal(wheres);

  total.value = count;
};

const initArticleTags = async () => {
  const tags = await getArticleTags();

  for (const tag of tags) {
    showTags.value.push({ text: tag });
  }
};

initArticleData();
initArticleTotalData();
initArticleTags();

const navigateToArticleDetail = (path: string) => {
  const lastPath = path.replaceAll('/', '=').substring(1);
  router.push(`/article/${lastPath}`);
};

const onChangePage = async (_page: number) => {
  page.value = _page;
  initArticleData();
  initArticleTotalData();
};

const onChangeTag = (tag: string) => {
  currentTag.value = tag;
  initArticleData(wheres.value);
  initArticleTotalData(wheres.value);
};

const onSearch = async () => {
  initArticleData(wheres.value);
  initArticleTotalData(wheres.value);
};

</script>

<template>
  <div class="h-full -mx-2 pr-4 overflow-y-auto -mt-4 max-lg:px-4">
    <div class="flex justify-between items-center sticky top-0 bg-neutral-900 z-30 max-lg:flex-col">
      <nav class="flex flex-wrap gap-x-8 gap-y-2 items-center min-h-14 py-2 max-lg:p-4 max-lg:mt-2">
        <button
          v-for="(item, idx) in showTags"
          :key="idx"
          class="text-sm hover:text-amber-300 cursor-pointer"
          :class="[currentTag === item.text ? 'text-amber-300' : 'text-white']"
          @click="onChangeTag(item.text)"
        >{{ item.text }}</button>
      </nav>
      <div>
        <input
          v-model="searchText"
          type="text"
          class="w-56 h-8 text-sm text-neutral-800 border rounded-md px-2 focus:border-amber-300 max-lg:hidden"
          placeholder="请输入文章名称..."
          @keydown.prevent.enter="onSearch"
        >
      </div>
    </div>

    <div v-if="data?.length" class="grid grid-cols-1 lg:grid-cols-3 gap-4 mt-4">
      <TransitionGroup name="list">
        <div
          v-for="(item, idx) in data"
          :key="item.id + idx"
          class="flex flex-col"
        >
          <div class="w-full h-40 rounded-tl-sm rounded-tr-sm overflow-hidden bg-neutral-800 border border-neutral-800 relative group">
            <img :src="item.image ? item.image : '/article-block.webp'" alt="image" class="w-full h-full group-hover:scale-110 transition duration-300" >
            <div class="absolute left-0 top-0 w-full h-full flex justify-center items-center opacity-0 hover:opacity-100">
              <div class="absolute left-0 top-0 w-full h-full bg-neutral-950 opacity-0 group-hover:opacity-70 shadow-md"/>
              <button
                class="bg-neutral-800 opacity-100 rounded-md w-12 h-12 flex justify-center items-center absolute shadow-neutral-950 z-10 cursor-pointer"
                @click="navigateToArticleDetail(item.path)"
              >
                <i class="iconfont icon-yanjing text-amber-300"/>
              </button>
            </div>
          </div>
          <div class="p-3 bg-neutral-900 shadow-sm shadow-neutral-950 border border-neutral-800 border-t-0">
            <div class="pb-2">
              <h2 class="text-white text-sm font-bold line-clamp-2 h-10">{{ item.title }}</h2>
              <p class="text-neutral-400 text-xs mt-2 line-clamp-2 h-8">{{ item.description }}</p>
            </div>
            <div class="flex gap-4 items-center">
              <!-- <span class="text-xs text-neutral-400">浏览：111</span> -->
              <span class="text-xs text-neutral-400">日期：{{ formatDate(item.date) }}</span>
            </div>
          </div>
        </div>
      </TransitionGroup>
    </div>

    <div v-if="data?.length === 0" class="w-full h-full flex flex-col justify-center items-center -translate-y-16">
      <i class="iconfont icon-quesheng text-7xl"/>
      <p class="text-sm font-bold text-neutral-300 mt-4">暂无更多内容了~</p>
    </div>

    <PageComp
      v-if="total > pageSize"
      :page="page"
      :page-size="pageSize"
      :total="total"
      @on-change="onChangePage"
    />
  </div>
</template>

<style lang="scss" scoped>
.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateY(30px);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.list-leave-active {
  display: none;
}
</style>